home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Tcl-Tk 8.0 / Pre-installed version / tk8.0 / generic / tkScrollbar.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-15  |  21.5 KB  |  692 lines  |  [TEXT/CWIE]

  1. /* 
  2.  * tkScrollbar.c --
  3.  *
  4.  *    This module implements a scrollbar widgets for the Tk
  5.  *    toolkit.  A scrollbar displays a slider and two arrows;
  6.  *    mouse clicks on features within the scrollbar cause
  7.  *    scrolling commands to be invoked.
  8.  *
  9.  * Copyright (c) 1990-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  11.  *
  12.  * See the file "license.terms" for information on usage and redistribution
  13.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  14.  *
  15.  * SCCS: @(#) tkScrollbar.c 1.94 97/07/31 09:12:44
  16.  */
  17.  
  18. #include "tkPort.h"
  19. #include "tkScrollbar.h"
  20. #include "default.h"
  21.  
  22. /*
  23.  * Information used for argv parsing.
  24.  */
  25.  
  26. Tk_ConfigSpec tkpScrollbarConfigSpecs[] = {
  27.     {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
  28.     DEF_SCROLLBAR_ACTIVE_BG_COLOR, Tk_Offset(TkScrollbar, activeBorder),
  29.     TK_CONFIG_COLOR_ONLY},
  30.     {TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
  31.     DEF_SCROLLBAR_ACTIVE_BG_MONO, Tk_Offset(TkScrollbar, activeBorder),
  32.     TK_CONFIG_MONO_ONLY},
  33.     {TK_CONFIG_RELIEF, "-activerelief", "activeRelief", "Relief",
  34.     DEF_SCROLLBAR_ACTIVE_RELIEF, Tk_Offset(TkScrollbar, activeRelief), 0},
  35.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  36.     DEF_SCROLLBAR_BG_COLOR, Tk_Offset(TkScrollbar, bgBorder),
  37.     TK_CONFIG_COLOR_ONLY},
  38.     {TK_CONFIG_BORDER, "-background", "background", "Background",
  39.     DEF_SCROLLBAR_BG_MONO, Tk_Offset(TkScrollbar, bgBorder),
  40.     TK_CONFIG_MONO_ONLY},
  41.     {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
  42.     (char *) NULL, 0, 0},
  43.     {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
  44.     (char *) NULL, 0, 0},
  45.     {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  46.     DEF_SCROLLBAR_BORDER_WIDTH, Tk_Offset(TkScrollbar, borderWidth), 0},
  47.     {TK_CONFIG_STRING, "-command", "command", "Command",
  48.     DEF_SCROLLBAR_COMMAND, Tk_Offset(TkScrollbar, command),
  49.     TK_CONFIG_NULL_OK},
  50.     {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
  51.     DEF_SCROLLBAR_CURSOR, Tk_Offset(TkScrollbar, cursor), TK_CONFIG_NULL_OK},
  52.     {TK_CONFIG_PIXELS, "-elementborderwidth", "elementBorderWidth",
  53.     "BorderWidth", DEF_SCROLLBAR_EL_BORDER_WIDTH,
  54.     Tk_Offset(TkScrollbar, elementBorderWidth), 0},
  55.     {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
  56.     "HighlightBackground", DEF_SCROLLBAR_HIGHLIGHT_BG,
  57.     Tk_Offset(TkScrollbar, highlightBgColorPtr), 0},
  58.     {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  59.     DEF_SCROLLBAR_HIGHLIGHT,
  60.     Tk_Offset(TkScrollbar, highlightColorPtr), 0},
  61.     {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
  62.     "HighlightThickness",
  63.     DEF_SCROLLBAR_HIGHLIGHT_WIDTH, Tk_Offset(TkScrollbar, highlightWidth), 0},
  64.     {TK_CONFIG_BOOLEAN, "-jump", "jump", "Jump",
  65.     DEF_SCROLLBAR_JUMP, Tk_Offset(TkScrollbar, jump), 0},
  66.     {TK_CONFIG_UID, "-orient", "orient", "Orient",
  67.     DEF_SCROLLBAR_ORIENT, Tk_Offset(TkScrollbar, orientUid), 0},
  68.     {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
  69.     DEF_SCROLLBAR_RELIEF, Tk_Offset(TkScrollbar, relief), 0},
  70.     {TK_CONFIG_INT, "-repeatdelay", "repeatDelay", "RepeatDelay",
  71.     DEF_SCROLLBAR_REPEAT_DELAY, Tk_Offset(TkScrollbar, repeatDelay), 0},
  72.     {TK_CONFIG_INT, "-repeatinterval", "repeatInterval", "RepeatInterval",
  73.     DEF_SCROLLBAR_REPEAT_INTERVAL, Tk_Offset(TkScrollbar, repeatInterval), 0},
  74.     {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
  75.     DEF_SCROLLBAR_TAKE_FOCUS, Tk_Offset(TkScrollbar, takeFocus),
  76.     TK_CONFIG_NULL_OK},
  77.     {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background",
  78.     DEF_SCROLLBAR_TROUGH_COLOR, Tk_Offset(TkScrollbar, troughColorPtr),
  79.     TK_CONFIG_COLOR_ONLY},
  80.     {TK_CONFIG_COLOR, "-troughcolor", "troughColor", "Background",
  81.     DEF_SCROLLBAR_TROUGH_MONO, Tk_Offset(TkScrollbar, troughColorPtr),
  82.     TK_CONFIG_MONO_ONLY},
  83.     {TK_CONFIG_PIXELS, "-width", "width", "Width",
  84.     DEF_SCROLLBAR_WIDTH, Tk_Offset(TkScrollbar, width), 0},
  85.     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
  86.     (char *) NULL, 0, 0}
  87. };
  88.  
  89. /*
  90.  * Forward declarations for procedures defined later in this file:
  91.  */
  92.  
  93. static int        ConfigureScrollbar _ANSI_ARGS_((Tcl_Interp *interp,
  94.                 TkScrollbar *scrollPtr, int argc, char **argv,
  95.                 int flags));
  96. static void        ScrollbarCmdDeletedProc _ANSI_ARGS_((
  97.                 ClientData clientData));
  98. static int        ScrollbarWidgetCmd _ANSI_ARGS_((ClientData clientData,
  99.                 Tcl_Interp *, int argc, char **argv));
  100.  
  101. /*
  102.  *--------------------------------------------------------------
  103.  *
  104.  * Tk_ScrollbarCmd --
  105.  *
  106.  *    This procedure is invoked to process the "scrollbar" Tcl
  107.  *    command.  See the user documentation for details on what
  108.  *    it does.
  109.  *
  110.  * Results:
  111.  *    A standard Tcl result.
  112.  *
  113.  * Side effects:
  114.  *    See the user documentation.
  115.  *
  116.  *--------------------------------------------------------------
  117.  */
  118.  
  119. int
  120. Tk_ScrollbarCmd(clientData, interp, argc, argv)
  121.     ClientData clientData;    /* Main window associated with
  122.                  * interpreter. */
  123.     Tcl_Interp *interp;        /* Current interpreter. */
  124.     int argc;            /* Number of arguments. */
  125.     char **argv;        /* Argument strings. */
  126. {
  127.     Tk_Window tkwin = (Tk_Window) clientData;
  128.     register TkScrollbar *scrollPtr;
  129.     Tk_Window new;
  130.  
  131.     if (argc < 2) {
  132.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  133.         argv[0], " pathName ?options?\"", (char *) NULL);
  134.     return TCL_ERROR;
  135.     }
  136.  
  137.     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
  138.     if (new == NULL) {
  139.     return TCL_ERROR;
  140.     }
  141.  
  142.     Tk_SetClass(new, "Scrollbar");
  143.     scrollPtr = TkpCreateScrollbar(new);
  144.  
  145.     TkSetClassProcs(new, &tkpScrollbarProcs, (ClientData) scrollPtr);
  146.  
  147.     /*
  148.      * Initialize fields that won't be initialized by ConfigureScrollbar,
  149.      * or which ConfigureScrollbar expects to have reasonable values
  150.      * (e.g. resource pointers).
  151.      */
  152.  
  153.     scrollPtr->tkwin = new;
  154.     scrollPtr->display = Tk_Display(new);
  155.     scrollPtr->interp = interp;
  156.     scrollPtr->widgetCmd = Tcl_CreateCommand(interp,
  157.         Tk_PathName(scrollPtr->tkwin), ScrollbarWidgetCmd,
  158.         (ClientData) scrollPtr, ScrollbarCmdDeletedProc);
  159.     scrollPtr->orientUid = NULL;
  160.     scrollPtr->vertical = 0;
  161.     scrollPtr->width = 0;
  162.     scrollPtr->command = NULL;
  163.     scrollPtr->commandSize = 0;
  164.     scrollPtr->repeatDelay = 0;
  165.     scrollPtr->repeatInterval = 0;
  166.     scrollPtr->borderWidth = 0;
  167.     scrollPtr->bgBorder = NULL;
  168.     scrollPtr->activeBorder = NULL;
  169.     scrollPtr->troughColorPtr = NULL;
  170.     scrollPtr->relief = TK_RELIEF_FLAT;
  171.     scrollPtr->highlightWidth = 0;
  172.     scrollPtr->highlightBgColorPtr = NULL;
  173.     scrollPtr->highlightColorPtr = NULL;
  174.     scrollPtr->inset = 0;
  175.     scrollPtr->elementBorderWidth = -1;
  176.     scrollPtr->arrowLength = 0;
  177.     scrollPtr->sliderFirst = 0;
  178.     scrollPtr->sliderLast = 0;
  179.     scrollPtr->activeField = 0;
  180.     scrollPtr->activeRelief = TK_RELIEF_RAISED;
  181.     scrollPtr->totalUnits = 0;
  182.     scrollPtr->windowUnits = 0;
  183.     scrollPtr->firstUnit = 0;
  184.     scrollPtr->lastUnit = 0;
  185.     scrollPtr->firstFraction = 0.0;
  186.     scrollPtr->lastFraction = 0.0;
  187.     scrollPtr->cursor = None;
  188.     scrollPtr->takeFocus = NULL;
  189.     scrollPtr->flags = 0;
  190.  
  191.     if (ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2, 0) != TCL_OK) {
  192.     Tk_DestroyWindow(scrollPtr->tkwin);
  193.     return TCL_ERROR;
  194.     }
  195.  
  196.     interp->result = Tk_PathName(scrollPtr->tkwin);
  197.     return TCL_OK;
  198. }
  199.  
  200. /*
  201.  *--------------------------------------------------------------
  202.  *
  203.  * ScrollbarWidgetCmd --
  204.  *
  205.  *    This procedure is invoked to process the Tcl command
  206.  *    that corresponds to a widget managed by this module.
  207.  *    See the user documentation for details on what it does.
  208.  *
  209.  * Results:
  210.  *    A standard Tcl result.
  211.  *
  212.  * Side effects:
  213.  *    See the user documentation.
  214.  *
  215.  *--------------------------------------------------------------
  216.  */
  217.  
  218. static int
  219. ScrollbarWidgetCmd(clientData, interp, argc, argv)
  220.     ClientData clientData;    /* Information about scrollbar
  221.                      * widget. */
  222.     Tcl_Interp *interp;            /* Current interpreter. */
  223.     int argc;                /* Number of arguments. */
  224.     char **argv;            /* Argument strings. */
  225. {
  226.     register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  227.     int result = TCL_OK;
  228.     size_t length;
  229.     int c;
  230.  
  231.     if (argc < 2) {
  232.     Tcl_AppendResult(interp, "wrong # args: should be \"",
  233.         argv[0], " option ?arg arg ...?\"", (char *) NULL);
  234.     return TCL_ERROR;
  235.     }
  236.     Tcl_Preserve((ClientData) scrollPtr);
  237.     c = argv[1][0];
  238.     length = strlen(argv[1]);
  239.     if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)) {
  240.     int oldActiveField;
  241.     if (argc == 2) {
  242.         switch (scrollPtr->activeField) {
  243.         case TOP_ARROW:        interp->result = "arrow1";    break;
  244.         case SLIDER:        interp->result = "slider";    break;
  245.         case BOTTOM_ARROW:    interp->result = "arrow2";    break;
  246.         }
  247.         goto done;
  248.     }
  249.     if (argc != 3) {
  250.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  251.             argv[0], " activate element\"", (char *) NULL);
  252.         goto error;
  253.     }
  254.     c = argv[2][0];
  255.     length = strlen(argv[2]);
  256.     oldActiveField = scrollPtr->activeField;
  257.     if ((c == 'a') && (strcmp(argv[2], "arrow1") == 0)) {
  258.         scrollPtr->activeField = TOP_ARROW;
  259.     } else if ((c == 'a') && (strcmp(argv[2], "arrow2") == 0)) {
  260.         scrollPtr->activeField = BOTTOM_ARROW;
  261.     } else if ((c == 's') && (strncmp(argv[2], "slider", length) == 0)) {
  262.         scrollPtr->activeField = SLIDER;
  263.     } else {
  264.         scrollPtr->activeField = OUTSIDE;
  265.     }
  266.     if (oldActiveField != scrollPtr->activeField) {
  267.         TkScrollbarEventuallyRedraw(scrollPtr);
  268.     }
  269.     } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
  270.         && (length >= 2)) {
  271.     if (argc != 3) {
  272.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  273.             argv[0], " cget option\"",
  274.             (char *) NULL);
  275.         goto error;
  276.     }
  277.     result = Tk_ConfigureValue(interp, scrollPtr->tkwin,
  278.         tkpScrollbarConfigSpecs, (char *) scrollPtr, argv[2], 0);
  279.     } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
  280.         && (length >= 2)) {
  281.     if (argc == 2) {
  282.         result = Tk_ConfigureInfo(interp, scrollPtr->tkwin,
  283.             tkpScrollbarConfigSpecs, (char *) scrollPtr,
  284.             (char *) NULL, 0);
  285.     } else if (argc == 3) {
  286.         result = Tk_ConfigureInfo(interp, scrollPtr->tkwin,
  287.             tkpScrollbarConfigSpecs, (char *) scrollPtr, argv[2], 0);
  288.     } else {
  289.         result = ConfigureScrollbar(interp, scrollPtr, argc-2, argv+2,
  290.             TK_CONFIG_ARGV_ONLY);
  291.     }
  292.     } else if ((c == 'd') && (strncmp(argv[1], "delta", length) == 0)) {
  293.     int xDelta, yDelta, pixels, length;
  294.     double fraction;
  295.  
  296.     if (argc != 4) {
  297.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  298.             argv[0], " delta xDelta yDelta\"", (char *) NULL);
  299.         goto error;
  300.     }
  301.     if ((Tcl_GetInt(interp, argv[2], &xDelta) != TCL_OK)
  302.         || (Tcl_GetInt(interp, argv[3], &yDelta) != TCL_OK)) {
  303.         goto error;
  304.     }
  305.     if (scrollPtr->vertical) {
  306.         pixels = yDelta;
  307.         length = Tk_Height(scrollPtr->tkwin) - 1
  308.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  309.     } else {
  310.         pixels = xDelta;
  311.         length = Tk_Width(scrollPtr->tkwin) - 1
  312.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  313.     }
  314.     if (length == 0) {
  315.         fraction = 0.0;
  316.     } else {
  317.         fraction = ((double) pixels / (double) length);
  318.     }
  319.     sprintf(interp->result, "%g", fraction);
  320.     } else if ((c == 'f') && (strncmp(argv[1], "fraction", length) == 0)) {
  321.     int x, y, pos, length;
  322.     double fraction;
  323.  
  324.     if (argc != 4) {
  325.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  326.             argv[0], " fraction x y\"", (char *) NULL);
  327.         goto error;
  328.     }
  329.     if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
  330.         || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
  331.         goto error;
  332.     }
  333.     if (scrollPtr->vertical) {
  334.         pos = y - (scrollPtr->arrowLength + scrollPtr->inset);
  335.         length = Tk_Height(scrollPtr->tkwin) - 1
  336.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  337.     } else {
  338.         pos = x - (scrollPtr->arrowLength + scrollPtr->inset);
  339.         length = Tk_Width(scrollPtr->tkwin) - 1
  340.             - 2*(scrollPtr->arrowLength + scrollPtr->inset);
  341.     }
  342.     if (length == 0) {
  343.         fraction = 0.0;
  344.     } else {
  345.         fraction = ((double) pos / (double) length);
  346.     }
  347.     if (fraction < 0) {
  348.         fraction = 0;
  349.     } else if (fraction > 1.0) {
  350.         fraction = 1.0;
  351.     }
  352.     sprintf(interp->result, "%g", fraction);
  353.     } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
  354.     if (argc != 2) {
  355.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  356.             argv[0], " get\"", (char *) NULL);
  357.         goto error;
  358.     }
  359.     if (scrollPtr->flags & NEW_STYLE_COMMANDS) {
  360.         char first[TCL_DOUBLE_SPACE], last[TCL_DOUBLE_SPACE];
  361.  
  362.         Tcl_PrintDouble(interp, scrollPtr->firstFraction, first);
  363.         Tcl_PrintDouble(interp, scrollPtr->lastFraction, last);
  364.         Tcl_AppendResult(interp, first, " ", last, (char *) NULL);
  365.     } else {
  366.         sprintf(interp->result, "%d %d %d %d", scrollPtr->totalUnits,
  367.             scrollPtr->windowUnits, scrollPtr->firstUnit,
  368.             scrollPtr->lastUnit);
  369.     }
  370.     } else if ((c == 'i') && (strncmp(argv[1], "identify", length) == 0)) {
  371.     int x, y, thing;
  372.  
  373.     if (argc != 4) {
  374.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  375.             argv[0], " identify x y\"", (char *) NULL);
  376.         goto error;
  377.     }
  378.     if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
  379.         || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
  380.         goto error;
  381.     }
  382.     thing = TkpScrollbarPosition(scrollPtr, x,y);
  383.     switch (thing) {
  384.         case TOP_ARROW:    interp->result = "arrow1";    break;
  385.         case TOP_GAP:    interp->result = "trough1";    break;
  386.         case SLIDER:    interp->result = "slider";    break;
  387.         case BOTTOM_GAP:    interp->result = "trough2";    break;
  388.         case BOTTOM_ARROW:    interp->result = "arrow2";    break;
  389.     }
  390.     } else if ((c == 's') && (strncmp(argv[1], "set", length) == 0)) {
  391.     int totalUnits, windowUnits, firstUnit, lastUnit;
  392.  
  393.     if (argc == 4) {
  394.         double first, last;
  395.  
  396.         if (Tcl_GetDouble(interp, argv[2], &first) != TCL_OK) {
  397.         goto error;
  398.         }
  399.         if (Tcl_GetDouble(interp, argv[3], &last) != TCL_OK) {
  400.         goto error;
  401.         }
  402.         if (first < 0) {
  403.         scrollPtr->firstFraction = 0;
  404.         } else if (first > 1.0) {
  405.         scrollPtr->firstFraction = 1.0;
  406.         } else {
  407.         scrollPtr->firstFraction = first;
  408.         }
  409.         if (last < scrollPtr->firstFraction) {
  410.         scrollPtr->lastFraction = scrollPtr->firstFraction;
  411.         } else if (last > 1.0) {
  412.         scrollPtr->lastFraction = 1.0;
  413.         } else {
  414.         scrollPtr->lastFraction = last;
  415.         }
  416.         scrollPtr->flags |= NEW_STYLE_COMMANDS;
  417.     } else if (argc == 6) {
  418.         if (Tcl_GetInt(interp, argv[2], &totalUnits) != TCL_OK) {
  419.         goto error;
  420.         }
  421.         if (totalUnits < 0) {
  422.         totalUnits = 0;
  423.         }
  424.         if (Tcl_GetInt(interp, argv[3], &windowUnits) != TCL_OK) {
  425.         goto error;
  426.         }
  427.         if (windowUnits < 0) {
  428.         windowUnits = 0;
  429.         }
  430.         if (Tcl_GetInt(interp, argv[4], &firstUnit) != TCL_OK) {
  431.         goto error;
  432.         }
  433.         if (Tcl_GetInt(interp, argv[5], &lastUnit) != TCL_OK) {
  434.         goto error;
  435.         }
  436.         if (totalUnits > 0) {
  437.         if (lastUnit < firstUnit) {
  438.             lastUnit = firstUnit;
  439.         }
  440.         } else {
  441.         firstUnit = lastUnit = 0;
  442.         }
  443.         scrollPtr->totalUnits = totalUnits;
  444.         scrollPtr->windowUnits = windowUnits;
  445.         scrollPtr->firstUnit = firstUnit;
  446.         scrollPtr->lastUnit = lastUnit;
  447.         if (scrollPtr->totalUnits == 0) {
  448.         scrollPtr->firstFraction = 0.0;
  449.         scrollPtr->lastFraction = 1.0;
  450.         } else {
  451.         scrollPtr->firstFraction = ((double) firstUnit)/totalUnits;
  452.         scrollPtr->lastFraction = ((double) (lastUnit+1))/totalUnits;
  453.         }
  454.         scrollPtr->flags &= ~NEW_STYLE_COMMANDS;
  455.     } else {
  456.         Tcl_AppendResult(interp, "wrong # args: should be \"",
  457.             argv[0], " set firstFraction lastFraction\" or \"",
  458.             argv[0],
  459.             " set totalUnits windowUnits firstUnit lastUnit\"",
  460.             (char *) NULL);
  461.         goto error;
  462.     }
  463.     TkpComputeScrollbarGeometry(scrollPtr);
  464.     TkScrollbarEventuallyRedraw(scrollPtr);
  465.     } else {
  466.     Tcl_AppendResult(interp, "bad option \"", argv[1],
  467.         "\": must be activate, cget, configure, delta, fraction, ",
  468.         "get, identify, or set", (char *) NULL);
  469.     goto error;
  470.     }
  471.     done:
  472.     Tcl_Release((ClientData) scrollPtr);
  473.     return result;
  474.  
  475.     error:
  476.     Tcl_Release((ClientData) scrollPtr);
  477.     return TCL_ERROR;
  478. }
  479.  
  480. /*
  481.  *----------------------------------------------------------------------
  482.  *
  483.  * ConfigureScrollbar --
  484.  *
  485.  *    This procedure is called to process an argv/argc list, plus
  486.  *    the Tk option database, in order to configure (or
  487.  *    reconfigure) a scrollbar widget.
  488.  *
  489.  * Results:
  490.  *    The return value is a standard Tcl result.  If TCL_ERROR is
  491.  *    returned, then interp->result contains an error message.
  492.  *
  493.  * Side effects:
  494.  *    Configuration information, such as colors, border width,
  495.  *    etc. get set for scrollPtr;  old resources get freed,
  496.  *    if there were any.
  497.  *
  498.  *----------------------------------------------------------------------
  499.  */
  500.  
  501. static int
  502. ConfigureScrollbar(interp, scrollPtr, argc, argv, flags)
  503.     Tcl_Interp *interp;            /* Used for error reporting. */
  504.     register TkScrollbar *scrollPtr;    /* Information about widget;  may or
  505.                      * may not already have values for
  506.                      * some fields. */
  507.     int argc;                /* Number of valid entries in argv. */
  508.     char **argv;            /* Arguments. */
  509.     int flags;                /* Flags to pass to
  510.                      * Tk_ConfigureWidget. */
  511. {
  512.     size_t length;
  513.  
  514.     if (Tk_ConfigureWidget(interp, scrollPtr->tkwin, tkpScrollbarConfigSpecs,
  515.         argc, argv, (char *) scrollPtr, flags) != TCL_OK) {
  516.     return TCL_ERROR;
  517.     }
  518.  
  519.     /*
  520.      * A few options need special processing, such as parsing the
  521.      * orientation or setting the background from a 3-D border.
  522.      */
  523.  
  524.     length = strlen(scrollPtr->orientUid);
  525.     if (strncmp(scrollPtr->orientUid, "vertical", length) == 0) {
  526.     scrollPtr->vertical = 1;
  527.     } else if (strncmp(scrollPtr->orientUid, "horizontal", length) == 0) {
  528.     scrollPtr->vertical = 0;
  529.     } else {
  530.     Tcl_AppendResult(interp, "bad orientation \"", scrollPtr->orientUid,
  531.         "\": must be vertical or horizontal", (char *) NULL);
  532.     return TCL_ERROR;
  533.     }
  534.  
  535.     if (scrollPtr->command != NULL) {
  536.     scrollPtr->commandSize = strlen(scrollPtr->command);
  537.     } else {
  538.     scrollPtr->commandSize = 0;
  539.     }
  540.  
  541.     /*
  542.      * Configure platform specific options.
  543.      */
  544.  
  545.     TkpConfigureScrollbar(scrollPtr);
  546.  
  547.     /*
  548.      * Register the desired geometry for the window (leave enough space
  549.      * for the two arrows plus a minimum-size slider, plus border around
  550.      * the whole window, if any).  Then arrange for the window to be
  551.      * redisplayed.
  552.      */
  553.  
  554.     TkpComputeScrollbarGeometry(scrollPtr);
  555.     TkScrollbarEventuallyRedraw(scrollPtr);
  556.     return TCL_OK;
  557. }
  558.  
  559. /*
  560.  *--------------------------------------------------------------
  561.  *
  562.  * TkScrollbarEventProc --
  563.  *
  564.  *    This procedure is invoked by the Tk dispatcher for various
  565.  *    events on scrollbars.
  566.  *
  567.  * Results:
  568.  *    None.
  569.  *
  570.  * Side effects:
  571.  *    When the window gets deleted, internal structures get
  572.  *    cleaned up.  When it gets exposed, it is redisplayed.
  573.  *
  574.  *--------------------------------------------------------------
  575.  */
  576.  
  577. void
  578. TkScrollbarEventProc(clientData, eventPtr)
  579.     ClientData clientData;    /* Information about window. */
  580.     XEvent *eventPtr;        /* Information about event. */
  581. {
  582.     TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  583.  
  584.     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
  585.     TkScrollbarEventuallyRedraw(scrollPtr);
  586.     } else if (eventPtr->type == DestroyNotify) {
  587.     TkpDestroyScrollbar(scrollPtr);
  588.     if (scrollPtr->tkwin != NULL) {
  589.         scrollPtr->tkwin = NULL;
  590.         Tcl_DeleteCommandFromToken(scrollPtr->interp,
  591.                     scrollPtr->widgetCmd);
  592.     }
  593.     if (scrollPtr->flags & REDRAW_PENDING) {
  594.         Tcl_CancelIdleCall(TkpDisplayScrollbar, (ClientData) scrollPtr);
  595.     }
  596.     /*
  597.      * Free up all the stuff that requires special handling, then
  598.      * let Tk_FreeOptions handle all the standard option-related
  599.      * stuff.
  600.      */
  601.     
  602.     Tk_FreeOptions(tkpScrollbarConfigSpecs, (char *) scrollPtr,
  603.         scrollPtr->display, 0);
  604.     Tcl_EventuallyFree((ClientData) scrollPtr, TCL_DYNAMIC);
  605.     } else if (eventPtr->type == ConfigureNotify) {
  606.     TkpComputeScrollbarGeometry(scrollPtr);
  607.     TkScrollbarEventuallyRedraw(scrollPtr);
  608.     } else if (eventPtr->type == FocusIn) {
  609.     if (eventPtr->xfocus.detail != NotifyInferior) {
  610.         scrollPtr->flags |= GOT_FOCUS;
  611.         if (scrollPtr->highlightWidth > 0) {
  612.         TkScrollbarEventuallyRedraw(scrollPtr);
  613.         }
  614.     }
  615.     } else if (eventPtr->type == FocusOut) {
  616.     if (eventPtr->xfocus.detail != NotifyInferior) {
  617.         scrollPtr->flags &= ~GOT_FOCUS;
  618.         if (scrollPtr->highlightWidth > 0) {
  619.         TkScrollbarEventuallyRedraw(scrollPtr);
  620.         }
  621.     }
  622.     }
  623. }
  624.  
  625. /*
  626.  *----------------------------------------------------------------------
  627.  *
  628.  * ScrollbarCmdDeletedProc --
  629.  *
  630.  *    This procedure is invoked when a widget command is deleted.  If
  631.  *    the widget isn't already in the process of being destroyed,
  632.  *    this command destroys it.
  633.  *
  634.  * Results:
  635.  *    None.
  636.  *
  637.  * Side effects:
  638.  *    The widget is destroyed.
  639.  *
  640.  *----------------------------------------------------------------------
  641.  */
  642.  
  643. static void
  644. ScrollbarCmdDeletedProc(clientData)
  645.     ClientData clientData;    /* Pointer to widget record for widget. */
  646. {
  647.     TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
  648.     Tk_Window tkwin = scrollPtr->tkwin;
  649.  
  650.     /*
  651.      * This procedure could be invoked either because the window was
  652.      * destroyed and the command was then deleted (in which case tkwin
  653.      * is NULL) or because the command was deleted, and then this procedure
  654.      * destroys the widget.
  655.      */
  656.  
  657.     if (tkwin != NULL) {
  658.     scrollPtr->tkwin = NULL;
  659.     Tk_DestroyWindow(tkwin);
  660.     }
  661. }
  662.  
  663. /*
  664.  *--------------------------------------------------------------
  665.  *
  666.  * TkScrollbarEventuallyRedraw --
  667.  *
  668.  *    Arrange for one or more of the fields of a scrollbar
  669.  *    to be redrawn.
  670.  *
  671.  * Results:
  672.  *    None.
  673.  *
  674.  * Side effects:
  675.  *    None.
  676.  *
  677.  *--------------------------------------------------------------
  678.  */
  679.  
  680. void
  681. TkScrollbarEventuallyRedraw(scrollPtr)
  682.     register TkScrollbar *scrollPtr;    /* Information about widget. */
  683. {
  684.     if ((scrollPtr->tkwin == NULL) || (!Tk_IsMapped(scrollPtr->tkwin))) {
  685.     return;
  686.     }
  687.     if ((scrollPtr->flags & REDRAW_PENDING) == 0) {
  688.     Tcl_DoWhenIdle(TkpDisplayScrollbar, (ClientData) scrollPtr);
  689.     scrollPtr->flags |= REDRAW_PENDING;
  690.     }
  691. }
  692.